<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title></title>
</head>
<body>

</body>
</html>
<script>
// 数组就是用 【】 这样的 对括号写的
var arr = ['a', 'b', 'c'];
// 也可以先定义 后赋值
var app=[];
app[0]='a'//......往下推送
// 任何类型的数据，都可以放入数组。

var arr = [
  {a: 1},
  [1, 2, 3],
  function() {return true;}
];

arr[0] // Object {a: 1}
arr[1] // [1, 2, 3]
arr[2] // function (){return true;}

// 数组的本质
// 本质上，数组属于一种特殊的对象。typeof运算符会返回数组的类型是object。

typeof [1, 2, 3] // "object"
// 上面代码表明，typeof运算符认为数组的类型就是对象
//   遍历一下 数组的属性
var arr = ['a', 'b', 'c'];

console.log(Object.keys(arr));//遍历出来属性是 0,2,3

// JavaScript 使用一个32位整数，保存数组的元素个数。这意味着，数组成员最多只有 4294967295 个（232 - 1）个，也就是说length属性的最大值就是 4294967295。

// 只要是数组，就一定有length属性。该属性是一个动态的值，等于键名中的最大整数加上1。

var arr = ['a', 'b'];
arr.length // 2

arr[2] = 'c';
arr.length // 3

arr[9] = 'd';
arr.length // 10

arr[1000] = 'e';
arr.length // 1001

//  for in  可以遍历对象也可以 遍历 数组  其实数组就是对象 对象就是数组
// for...in循环不仅可以遍历对象，也可以遍历数组，毕竟数组只是一种特殊对象。

var a = [1, 2, 3];

for (var i in a) {
  console.log(a[i]);
}
// 1
// 2
// 3
// 但是，for...in不仅会遍历数组所有的数字键，还会遍历非数字键。

var a = [1, 2, 3];
a.foo = true;

for (var key in a) {
  console.log(key);
}
// 0
// 1
// 2
// foo
// 上面代码在遍历数组时，也遍历到了非整数键foo。所以，不推荐使用for...in遍历数组。

// 数组的遍历可以考虑使用for循环或while循环。

var a = [1, 2, 3];

// for循环
for(var i = 0; i < a.length; i++) {
  console.log(a[i]);
}

// while循环
var i = 0;
while (i < a.length) {
  console.log(a[i]);
  i++;
}

var l = a.length;
while (l--) {
  console.log(a[l]);
}
// 上面代码是三种遍历数组的写法。最后一种写法是逆向遍历，即从最后一个元素向第一个元素遍历。

// 数组的forEach方法，也可以用来遍历数组，详见《标准库》的 Array 对象一章。
// 
var colors = ['red', 'green', 'blue'];
colors.forEach(function (color) {
  console.log(color);
});
// red
// green
// blue
数组的空位
// 当数组的某个位置是空元素，即两个逗号之间没有任何值，我们称该数组存在空位（hole）。

var a = [1, , 1];
a.length // 3
// 上面代码表明，数组的空位不影响length属性。

// 需要注意的是，如果最后一个元素后面有逗号，并不会产生空位。也就是说，有没有这个逗号，结果都是一样的。

var a = [1, 2, 3,];

a.length // 3
a // [1, 2, 3]
// 上面代码中，数组最后一个成员后面有一个逗号，这不影响length属性的值，与没有这个逗号时效果一样。

// 数组的空位是可以读取的，返回undefined。

var a = [, , ,];
a[1] // undefined
// 使用delete命令删除一个数组成员，会形成空位，并且不会影响length属性。

var a = [1, 2, 3];
delete a[1];

a[1] // undefined
a.length // 3
// 上面代码用delete命令删除了数组的第二个元素，这个位置就形成了空位，但是对length属性没有影响。也就是说，length属性不过滤空位。所以，使用length属性进行数组遍历，一定要非常小心。

// 数组的某个位置是空位，与某个位置是undefined，是不一样的。如果是空位，使用数组的forEach方法、for...in结构、以及Object.keys方法进行遍历，空位都会被跳过。

var a = [, , ,];

a.forEach(function (x, i) {
  console.log(i + '. ' + x);
})
// 不产生任何输出

for (var i in a) {
  console.log(i);
}
// 不产生任何输出

Object.keys(a)
// []
// 如果某个位置是undefined，遍历的时候就不会被跳过。

var a = [undefined, undefined, undefined];

a.forEach(function (x, i) {
  console.log(i + '. ' + x);
});
// 0. undefined
// 1. undefined
// 2. undefined

for (var i in a) {
  console.log(i);
}
// 0
// 1
// 2

Object.keys(a)
// ['0', '1', '2']
// 这就是说，空位就是数组没有这个元素，所以不会被遍历到，而undefined则表示数组有这个元素，值是undefined，所以遍历不会跳过。

// 类似数组的对象
// 如果一个对象的所有键名都是正整数或零，并且有length属性，那么这个对象就很像数组，语法上称为“类似数组的对象”（array-like object）。

var obj = {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3
};

obj[0] // 'a'
obj[1] // 'b'
obj.length // 3
obj.push('d') // TypeError: obj.push is not a function
// 上面代码中，对象obj就是一个类似数组的对象。但是，“类似数组的对象”并不是数组，因为它们不具备数组特有的方法。对象obj没有数组的push方法，使用该方法就会报错。

// “类似数组的对象”的根本特征，就是具有length属性。只要有length属性，就可以认为这个对象类似于数组。但是有一个问题，这种length属性不是动态值，不会随着成员的变化而变化。
// 
var obj = {
  length: 0
};
obj[3] = 'd';
obj.length // 0
// 上面代码为对象obj添加了一个数字键，但是length属性没变。这就说明了obj不是数组。
// 
// 典型的“类似数组的对象”是函数的arguments对象，以及大多数 DOM 元素集，还有字符串。

// arguments对象
function args() { return arguments }
var arrayLike = args('a', 'b');

arrayLike[0] // 'a'
arrayLike.length // 2
arrayLike instanceof Array // false

// DOM元素集
var elts = document.getElementsByTagName('h3');
elts.length // 3
elts instanceof Array // false

// 字符串
'abc'[1] // 'b'
'abc'.length // 3
'abc' instanceof Array // false
// 上面代码包含三个例子，它们都不是数组（instanceof运算符返回false），但是看上去都非常像数组。

// 数组的slice方法可以将“类似数组的对象”变成真正的数组。

var arr = Array.prototype.slice.call(arrayLike);
// 除了转为真正的数组，“类似数组的对象”还有一个办法可以使用数组的方法，就是通过call()把数组的方法放到对象上面。

function print(value, index) {
  console.log(index + ' : ' + value);
}

Array.prototype.forEach.call(arrayLike, print);
// 上面代码中，arrayLike代表一个类似数组的对象，本来是不可以使用数组的forEach()方法的，但是通过call()，可以把forEach()嫁接到arrayLike上面调用。

// 下面的例子就是通过这种方法，在arguments对象上面调用forEach方法。

// forEach 方法
function logArgs() {
  Array.prototype.forEach.call(arguments, function (elem, i) {
    console.log(i + '. ' + elem);
  });
}

// 等同于 for 循环
function logArgs() {
  for (var i = 0; i < arguments.length; i++) {
    console.log(i + '. ' + arguments[i]);
  }
}
// 字符串也是类似数组的对象，所以也可以用Array.prototype.forEach.call遍历。

Array.prototype.forEach.call('abc', function (chr) {
  console.log(chr);
});
// a
// b
// c
// 注意，这种方法比直接使用数组原生的forEach要慢，所以最好还是先将“类似数组的对象”转为真正的数组，然后再直接调用数组的forEach方法。

var arr = Array.prototype.slice.call('abc');
arr.forEach(function (chr) {
  console.log(chr);
});
// a
// b
// c
